package com.hb.model;

import com.hb.interfaces.ShoppingCart;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class StoreService {
    private ShoppingCart shoppingCart;

    // 假设我们要将 ShoppingCart bean 注入到单例 StoreService bean 的 Setter 方法中。因为 StoreService 是一个单例的 bean，会在 Spring 应用上下文加载
    // 的时候创建。当它创建的时候，Spring 会试图将 ShoppingCart bean 注入到 setShoppingCart() 方法中。但是 ShoppingCart bean 是会话作用域的，此时并不存在。
    // 直到某个用户进入系统，创建了会话之后，才会出现ShoppingCart实例。
    // 另外，系统中将会有多个 ShoppingCart 实例：每个用户一个。我们并不想让 Spring 注入某个固定的 ShoppingCart 实例到 StoreService 中。
    // 我们希望的是当 StoreService 处理购物车功能时，它所使用的 ShoppingCart 实例恰好是当前会话所对应的那一个。
    // Spring 并不会将实际的 ShoppingCart bean 注入到 StoreService 中，Spring 会注入一个到 ShoppingCart bean 的代理，这个代理会暴露与 ShoppingCart 相同的方法，
    // 所以 StoreService 会认为它就是一个购物车。但是，当 StoreService 调用 ShoppingCart 的方法时，代理会对其进行懒解析并将调用委托给会话作用域内真正的 ShoppingCart bean。
    // 现在，我们带着对这个作用域的理解，讨论一下 proxyMode 属性。如配置所示，proxyMode 属性被设置成了 ScopedProxyMode.INTERFACES，这表明这个代理要实现 ShoppingCart 接口，
    // 并将调用委托给实现 bean。如果 ShoppingCart 是接口而不是类的话，这是可以的（也是最为理想的代理模式）。但如果 ShoppingCart 是一个具体的类的话，Spring就没有办法创建
    // 基于接口的代理了。此时，它必须使用 CGLib 来生成基于类的代理。所以，如果 bean 类型是具体类的话，我们必须要将 proxyMode 属性设置为 ScopedProxyMode.TARGET_CLASS，
    // 以此来表明要以生成目标类扩展的方式创建代理。
    @Autowired
    public void setShoppingCart(ShoppingCart shoppingCart) {
        this.shoppingCart = shoppingCart;
    }
}
